package com.navi.mould1.reportUtils;


import java.util.Map;

/**
 * 字符串工具类
 */
public final class LKingStringUtils {
    /**
     * 构造方法
     */
    private LKingStringUtils() {
    }


    /** 空 */
    public static final String EMPTY = "";

    /** 空格 */
    public static final String SPACE = " ";

    /** 点 */
    public static final String DOT = ".";

    /** 分割线 */
    public static final String SEPARATOR = "/";

    /** 反斜线 */
    public static final String BACKLASH = "\\";

    /** 下划线 */
    public static final String UNDERLINE = "_";

    /** java空 */
    public static final String NULL = "null";

    /** javascript空 */
    public static final String UNDEFINED = "undefined";

    /** EL表达式前缀 */
    public static final String EL_PREFIX = "${";

    /** EL表达式后缀 */
    public static final String EL_SUFFIX = "}";

    /** 为真的字符串 */
    public static final String[] TRUES = { "Y", "T", "ON", "YES", "TRUE", "1" };

    /** 为假的字符串 */
    public static final String[] FALSES = { "N", "F", "OFF", "NO", "FALSE", "0" };


    /**
     * 去除空格。并将认定java中的空(null)和javascript(undefined)中的空都为空。
     *
     * <pre>
     * assertEquals(LKStringUtils.trimToEmpty(null), "");
     * assertEquals(LKStringUtils.trimToEmpty(""), "");
     * assertEquals(LKStringUtils.trimToEmpty(" "), "");
     * assertEquals(LKStringUtils.trimToEmpty("null"), "");
     * assertEquals(LKStringUtils.trimToEmpty(" null"), "");
     * assertEquals(LKStringUtils.trimToEmpty("null "), "");
     * assertEquals(LKStringUtils.trimToEmpty("undefined"), "");
     * assertEquals(LKStringUtils.trimToEmpty(" undefined"), "");
     * assertEquals(LKStringUtils.trimToEmpty("undefined "), "");
     *
     * assertEquals(LKStringUtils.trimToEmpty("other"), "other");
     * assertEquals(LKStringUtils.trimToEmpty(" other"), "other");
     * assertEquals(LKStringUtils.trimToEmpty("other "), "other");
     * </pre>
     *
     * @param cs 字符串
     * @return 去除空格后的字符串
     */
    public static String trimToEmpty(final CharSequence cs) {
        if ((cs == null) || EMPTY.equals(cs)) {
            return EMPTY;
        }
        final String str = cs.toString().trim();
        if (NULL.equalsIgnoreCase(str) || UNDEFINED.equals(str)) {
            return EMPTY;
        }
        return str;
    }


    /**
     * 判断字符数组是否为空
     *
     * <pre>
     * assertTrue(LKStringUtils.isBlank(null));
     * assertTrue(LKStringUtils.isBlank(""));
     * assertTrue(LKStringUtils.isBlank(" "));
     * assertTrue(LKStringUtils.isBlank("null"));
     * assertTrue(LKStringUtils.isBlank(" null"));
     * assertTrue(LKStringUtils.isBlank("null "));
     * assertTrue(LKStringUtils.isBlank("undefined"));
     * assertTrue(LKStringUtils.isBlank(" undefined"));
     * assertTrue(LKStringUtils.isBlank("undefined "));
     *
     * assertFalse(LKStringUtils.isBlank("other"));
     * assertFalse(LKStringUtils.isBlank(" other"));
     * assertFalse(LKStringUtils.isBlank("other "));
     * </pre>
     *
     * @param cs 字符数组
     * @return 为空时返回true，否则返回false。
     */
    public static boolean isBlank(final CharSequence cs) {
        return EMPTY.equals(trimToEmpty(cs));
    }


    /**
     * 判断字符数组是否不为空
     *
     * <pre>
     * assertFalse(LKStringUtils.isNotBlank(null));
     * assertFalse(LKStringUtils.isNotBlank(""));
     * assertFalse(LKStringUtils.isNotBlank(" "));
     * assertFalse(LKStringUtils.isNotBlank("null"));
     * assertFalse(LKStringUtils.isNotBlank(" null"));
     * assertFalse(LKStringUtils.isNotBlank("null "));
     * assertFalse(LKStringUtils.isNotBlank("undefined"));
     * assertFalse(LKStringUtils.isNotBlank(" undefined"));
     * assertFalse(LKStringUtils.isNotBlank("undefined "));
     *
     * assertTrue(LKStringUtils.isNotBlank("other"));
     * assertTrue(LKStringUtils.isNotBlank(" other"));
     * assertTrue(LKStringUtils.isNotBlank("other "));
     *
     * </pre>
     *
     * @param cs 字符数组
     * @return 不为空时返回true，否则返回false。
     */
    public static boolean isNotBlank(final CharSequence cs) {
        return !isBlank(cs);
    }


    /**
     * 转换成String类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * </pre>
     *
     * @param cs 字符数组。
     * @param defaultValue 默认值
     * @return String类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static String toString(final CharSequence cs, final String defaultValue) {
        if (isBlank(cs)) {
            return defaultValue;
        }
        return trimToEmpty(cs);
    }


    /**
     * 转换成Byte类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Byte类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Byte toByte(final CharSequence cs, final Byte defaultValue) {
        if (isNotBlank(cs)) {
            try {
                return Byte.parseByte(trimToEmpty(cs));
            } catch (final NumberFormatException e) {
                // ignore this
            }
        }
        return defaultValue;
    }


    /**
     * 转换成Short类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Short类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Short toShort(final CharSequence cs, final Short defaultValue) {
        if (isNotBlank(cs)) {
            try {
                return Short.parseShort(trimToEmpty(cs));
            } catch (final NumberFormatException e) {
                // ignore this
            }
        }
        return defaultValue;
    }


    /**
     * 转换成Integer类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Integer类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Integer toInteger(final CharSequence cs, final Integer defaultValue) {
        if (isNotBlank(cs)) {
            try {
                return Integer.parseInt(trimToEmpty(cs));
            } catch (final NumberFormatException e) {
                // ignore this
            }
        }
        return defaultValue;
    }


    /**
     * 转换成Long类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Long类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Long toLong(final CharSequence cs, final Long defaultValue) {
        if (isNotBlank(cs)) {
            try {
                return Long.parseLong(trimToEmpty(cs));
            } catch (final NumberFormatException e) {
                // ignore this
            }
        }
        return defaultValue;
    }


    /**
     * 转换成Float类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Float类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Float toFloat(final CharSequence cs, final Float defaultValue) {
        if (isNotBlank(cs)) {
            try {
                return Float.parseFloat(trimToEmpty(cs));
            } catch (final NumberFormatException e) {
                // ignore this
            }
        }
        return defaultValue;
    }


    /**
     * 转换成Double类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Double类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Double toDouble(final CharSequence cs, final Double defaultValue) {
        if (isNotBlank(cs)) {
            try {
                return Double.parseDouble(trimToEmpty(cs));
            } catch (final NumberFormatException e) {
                // ignore this
            }
        }
        return defaultValue;
    }


    /**
     * 转换成Boolean类型值。
     *
     * <pre>
     * 当cs为空时返回defaultValue。否则返回去空格后的cs。
     * 如果转型失败，则将返回defaultValue。
     * TRUES中定义的都将视为真。数字大于0也都将视为真。
     * </pre>
     *
     * @param cs 字符数组
     * @param defaultValue 默认值
     * @return Boolean类型值
     * @see LKingStringUtils#isBlank(CharSequence)
     * @see LKingStringUtils#trimToEmpty(CharSequence)
     */
    public static Boolean toBoolean(final CharSequence cs, final Boolean defaultValue) {
        if (isNotBlank(cs)) {
            final String str = trimToEmpty(cs);
            for (final String t : TRUES) {
                if (t.equalsIgnoreCase(str)) {
                    return Boolean.TRUE;
                }
            }
            for (final String t : FALSES) {
                if (t.equalsIgnoreCase(str)) {
                    return Boolean.FALSE;
                }
            }
            try {
                return (Double.parseDouble(str) > 0) ? Boolean.TRUE : Boolean.FALSE;
            } catch (final Exception e) {
            }
        }
        return defaultValue;
    }


    /**
     * 替换字符串
     * @param regex 正则表达式
     * @param input 待匹配字符串
     * @param replaceStr 替换字符串
     * @return 替换后的字符串
     */
    public static String replaceAll(final String regex, final String input, final String replaceStr) {
        return LKingMatcherUtils.getMatcher(regex, input).replaceAll(replaceStr);
    }


    /**
     * 将字符串格式化成单行字符串
     * @param cs 待转换字符串
     * @return ""或单行字符串
     */
    public static String format2SingleLine(final CharSequence cs) {
        String str = trimToEmpty(cs);
        if (EMPTY.equals(str)) {
            return EMPTY;
        }

        // 先将所有换行制表符空格等替换成空格
        str = replaceAll("[\r]+", str, SPACE);
        str = replaceAll("[\n]+", str, SPACE);
        str = replaceAll("[\t]+", str, SPACE);
        str = replaceAll("[\b]+", str, SPACE);

        // 最后将所有空格替换成空格，此部将使得连续空格变成一个空格。
        str = replaceAll("[ ]+", str, SPACE);

        // 返回结果
        return str;
    }


    /**
     * 首字母大写
     * @param str 待转换字符串
     * @return 首字母大写字符串
     */
    public static String capitalize(final String str) {
        final String result = trimToEmpty(str);
        if (EMPTY.equals(result)) {
            return EMPTY;
        }

        final char firstChar = result.charAt(0);
        if ((firstChar >= 'a') && (firstChar <= 'z')) {
            return new StringBuilder().append((char) (firstChar - 32)).append(result.substring(1)).toString();
        }
        return result;
    }


    /**
     * 下划线转驼峰
     *
     * <pre>
     * assertEquals(LKStringUtils.underlineToHump("abcdefghijk"), "abcdefghijk");
     * assertEquals(LKStringUtils.underlineToHump("ABCDEFGHIJK"), "abcdefghijk");
     * assertEquals(LKStringUtils.underlineToHump("Abcdefghijk"), "Abcdefghijk");
     * assertEquals(LKStringUtils.underlineToHump("abcdefghijK"), "abcdefghijK");
     * assertEquals(LKStringUtils.underlineToHump("abcde_Fghijk"), "abcdeFghijk");
     * assertEquals(LKStringUtils.underlineToHump("Abcde_FghijK"), "AbcdeFghijK");
     * assertEquals(LKStringUtils.underlineToHump("1abcdefghijk"), "1abcdefghijk");
     * assertEquals(LKStringUtils.underlineToHump("abcdefghijk1"), "abcdefghijk1");
     * assertEquals(LKStringUtils.underlineToHump("abcde1fghijk"), "abcde1fghijk");
     * assertEquals(LKStringUtils.underlineToHump("1abcde1fghijk1"), "1abcde1fghijk1");
     * assertEquals(LKStringUtils.underlineToHump("1abcde1_Fghijk1"), "1abcde1Fghijk1");
     * assertEquals(LKStringUtils.underlineToHump("1abcde1_FGhijk1"), "1abcde1FGhijk1");
     * assertEquals(LKStringUtils.underlineToHump("1ab_Cde1_FGhijk1"), "1abCde1FGhijk1");
     * assertEquals(LKStringUtils.underlineToHump("USING_STATUS"), "usingStatus");
     * </pre>
     *
     * @param str 下划线
     * @return 驼峰
     */
    public static String underlineToHump(final String str) {
        // 先判断输入值是否为标准的下划线标识。即除下划线和数字以外，全部都是大写字母，或者全部都是小写字母。
        final StringBuilder result = new StringBuilder();

        if (LKingMatcherUtils.getMatcher("[0-9_a-z]*", str).matches() || LKingMatcherUtils.getMatcher("[0-9_A-Z]*", str).matches()) {// 标准的下划线标识，转换为标准的驼峰标识。即abcDefGh
            result.append(str.toLowerCase());// 首先全部转换为小写
            for (int i = result.length() - 1; i >= 0; i--) {// 倒序遍历
                if (result.charAt(i) == '_') {// 如果当前字符是下划线，则将本字符删除，然后将移入该位置的字符转换为大写。
                    result.deleteCharAt(i);
                    result.setCharAt(i, Character.toUpperCase(result.charAt(i)));
                }
            }
        } else {
            // 非标准的下划线标识，则只将下划线去除，并将下划线后面的字符转换为大写。
            final String[] strs = trimToEmpty(str).split(UNDERLINE);
            for (int i = 0; i < strs.length; i++) {
                result.append(i == 0 ? strs[i] : capitalize(strs[i]));
            }
        }

        return result.toString();
    }


    /**
     * 驼峰转下划线
     *
     * <pre>
     * assertEquals(LKStringUtils.humpToUnderline("abcdefghijk"), "ABCDEFGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("Abcdefghijk"), "ABCDEFGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("abcdefghijK"), "ABCDEFGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("abcdeFghijk"), "ABCDE_FGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("AbcdeFghijK"), "ABCDE_FGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("1abcdefghijk"), "1ABCDEFGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("abcdefghijk1"), "ABCDEFGHIJK1");
     * assertEquals(LKStringUtils.humpToUnderline("abcde1fghijk"), "ABCDE1FGHIJK");
     * assertEquals(LKStringUtils.humpToUnderline("1abcde1fghijk1"), "1ABCDE1FGHIJK1");
     * assertEquals(LKStringUtils.humpToUnderline("1abcde1Fghijk1"), "1ABCDE1_FGHIJK1");
     * assertEquals(LKStringUtils.humpToUnderline("1abcde1FGhijk1"), "1ABCDE1_FGHIJK1");
     * assertEquals(LKStringUtils.humpToUnderline("1abCde1FGhijk1"), "1AB_CDE1_FGHIJK1");
     * assertEquals(LKStringUtils.humpToUnderline("usingStatus"), "USING_STATUS");
     * </pre>
     *
     * @param str 驼峰
     * @return 下划线
     */
    public static String humpToUnderline(final String str) {
        if (LKingMatcherUtils.getMatcher("[0-9_A-Z]*", str).matches()) {// 全部都是大写字母，数字，下划线，直接返回。
            return str;
        }
        if (LKingMatcherUtils.getMatcher("[0-9_a-z]*", str).matches()) {// 全部都是小写字母，数字，下划线，返回转大写。
            return str.toUpperCase();
        }

        final StringBuilder sb = new StringBuilder(str);
        for (int i = 1; i < (sb.length() - 1); i++) {
            if (Character.isUpperCase(sb.charAt(i))) {// 当前字符是大写字母
                final char pre = sb.charAt(i - 1);
                if (Character.isLowerCase(pre) || Character.isDigit(pre)) {// 前一字符是小写字母或数字
                    sb.insert(i++, UNDERLINE);
                }
            }
        }
        return sb.toString().toUpperCase();// 转换为大写
    }


    /**
     * 连接字符串
     * @param strs 字符串数组
     * @return 字符串
     */
    public static String join(final String... strs) {
        return join(strs, null, 0, -1);
    }


    /**
     * 连接字符串
     * @param strs 字符串数组
     * @param separator 连接符
     * @return 字符串
     */
    public static String join(final String[] strs, final String separator) {
        return join(strs, separator, 0, -1);
    }


    /**
     * 连接字符串
     * @param strs 字符串数组
     * @param separator 连接符
     * @param startIndex 开始位置
     * @param endIndex 结束位置
     * @return 字符串
     */
    public static String join(final String[] strs, final String separator, final int startIndex, final int endIndex) {
        if (strs == null) {
            return EMPTY;
        }

        final String sep = trimToEmpty(separator);
        int start = startIndex;
        int end = endIndex;

        if (start < 0) {
            start = 0;
        }
        if (end < 0) {
            end = strs.length;
        }

        final int noOfItems = end - start;
        if (noOfItems <= 0) {
            return EMPTY;
        }

        final StringBuilder buf = new StringBuilder(noOfItems * 16);

        for (int i = start; i < end; i++) {
            if (i > start) {
                buf.append(sep);
            }
            if (strs[i] != null) {
                buf.append(trimToEmpty(strs[i]));
            }
        }
        return buf.toString();
    }


    /**
     * 补零
     *
     * <pre>
     * assertEquals(LKStringUtils.fillZero("3", 1, true), "3");
     * assertEquals(LKStringUtils.fillZero("3", 2, true), "03");
     * assertEquals(LKStringUtils.fillZero("33", 1, true), "33");
     * assertEquals(LKStringUtils.fillZero("33", 2, true), "33");
     * assertEquals(LKStringUtils.fillZero("33", 3, true), "033");
     * assertEquals(LKStringUtils.fillZero("3", 1, false), "3");
     * assertEquals(LKStringUtils.fillZero("3", 2, false), "30");
     * assertEquals(LKStringUtils.fillZero("33", 1, false), "33");
     * assertEquals(LKStringUtils.fillZero("33", 2, false), "33");
     * assertEquals(LKStringUtils.fillZero("33", 3, false), "330");
     * </pre>
     *
     * @param number 当前数字
     * @param digit 显示位数
     * @param before true：在前面补零；false：在后面补零。
     * @return 补零后的结果
     */
    public static String fillZero(final String number, final int digit, final boolean before) {
        final char[] cs = number.toCharArray();
        if (digit <= cs.length) {
            return String.valueOf(cs);
        } else {
            final char[] ncs = new char[digit];
            for (int i = 0; i < ncs.length; i++) {
                ncs[i] = '0';
            }
            if (before) {
                for (int i = ncs.length - 1; i > (digit - number.length() - 1); i--) {
                    ncs[i] = cs[i - (digit - number.length())];
                }
            } else {
                for (int i = 0; i < cs.length; i++) {
                    ncs[i] = cs[i];
                }
            }
            return String.valueOf(ncs);
        }
    }


    /**
     * 补零
     * @param number 当前数字
     * @param digit 显示位数
     * @return 补零后的结果
     * @see LKingStringUtils#fillZero(String, int, boolean)
     */
    public static String fillZero(final String number, final int digit) {
        return fillZero(number, digit, true);
    }


    /**
     * 补零
     * @param number 当前数字
     * @param digit 显示位数
     * @return 补零后的结果
     * @see LKingStringUtils#fillZero(String, int, boolean)
     */
    public static String fillZero(final int number, final int digit) {
        return fillZero(String.valueOf(number), digit, true);
    }


    /**
     * 替换数据变量
     * @param str 待替换字符串
     * @param datas 数据集合。key为待替换的内容，value为替换内容。key可以直接使用单词，或使用#word，或使用${word}，当这样使用时，str中也必须同样书写。
     * @return 替换后的字符串
     */
    public static String replaceDatas(String str, final Map<String, String> datas) {
        if ((str == null) || EMPTY.equals(str)) {
            return str;
        }
        if ((datas != null) && !datas.isEmpty()) {
            for (final Map.Entry<String, String> entry : datas.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if (key == null) {
                    continue;
                }
                if (key.startsWith(EL_PREFIX) && key.endsWith(EL_SUFFIX)) {
                    key = "\\$\\{" + key.substring(2, key.length() - 1) + "\\}";
                }
                if (value == null) {
                    value = EMPTY;
                } else {
                }
                str = str.replaceAll(key, value);
            }
        }
        return str;
    }


    /**
     * EL表达式
     * @param key 键
     * @return EL表达式
     */
    public static String el(String key) {
        return EL_PREFIX + key + EL_SUFFIX;
    }
}
